#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time    : 2024/11/28 16:45
@Author  : lxc
@File    : main.py
@Desc    :
"""
import os.path
import time
from multiprocessing import Process
from crawler import Crawler
from utils.create_new_table import create_new_table
from utils.log_util import Logger
from utils.models import *
import datetime
import json
import sys
import threading
from openpyxl import Workbook
import sqlite3
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QCheckBox, \
    QFileDialog, QComboBox, QLineEdit, QTableWidget, QTableWidgetItem, QMessageBox, QSpinBox, QFrame

logger = Logger().get_logger('log')

def add_line(main_layout):
    # 创建一条横线
    line = QFrame()
    line.setFrameShape(QFrame.HLine)  # 设置为水平线
    line.setFrameShadow(QFrame.Sunken)  # 设置阴影样式，Sunken 使线条看起来凹陷
    main_layout.addWidget(line)  # main_layout 是你的主布局
    return main_layout

class MyApp(QWidget):
    def __init__(self):
        super().__init__()
        self.conf = {}
        self.conf['browser'] = 'chrome/Chrome.exe'
        self.init_ui()
        self.is_verify_input = False
        self.table_name = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        self.crawler = None

    def init_ui(self):
        # 主布局
        main_layout = QVBoxLayout()
        # 左上角的 logo 部分
        self.setWindowIcon(QIcon('logo.ico'))
        main_layout = add_line(main_layout)  # 创建一条横线
        # 勾选框区域: 同一行显示
        checkbox_layout = QHBoxLayout()
        # 设置勾选框并默认选中
        self.conf['checkbox_balance'] = QCheckBox('余额')
        self.conf['checkbox_balance'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_balance'])

        self.conf['checkbox_belonging'] = QCheckBox('归属地')
        self.conf['checkbox_belonging'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_belonging'])

        self.conf['checkbox_paytype'] = QCheckBox('付费方式')
        self.conf['checkbox_paytype'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_paytype'])

        self.conf['checkbox_service_state'] = QCheckBox('服务状态')
        self.conf['checkbox_service_state'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_service_state'])

        self.conf['checkbox_additional_num'] = QCheckBox('副卡数量')
        self.conf['checkbox_additional_num'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_additional_num'])

        self.conf['checkbox_gpon'] = QCheckBox('光猫型号')
        self.conf['checkbox_gpon'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_gpon'])

        self.conf['checkbox_bandwidth'] = QCheckBox('带宽')
        self.conf['checkbox_bandwidth'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_bandwidth'])

        self.conf['checkbox_avg_3month'] = QCheckBox('近3月平均出账')
        self.conf['checkbox_avg_3month'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_avg_3month'])

        self.conf['checkbox_fusion_type'] = QCheckBox('融合类型')
        self.conf['checkbox_fusion_type'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_fusion_type'])

        self.conf['checkbox_access_time'] = QCheckBox('入网时间')
        self.conf['checkbox_access_time'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_access_time'])

        self.conf['checkbox_usage_minutes'] = QCheckBox('套餐使用查询')
        self.conf['checkbox_usage_minutes'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_usage_minutes'])

        self.conf['checkbox_usage_flow'] = QCheckBox('套餐明细查询')
        self.conf['checkbox_usage_flow'].setChecked(True)  # 默认勾选
        checkbox_layout.addWidget(self.conf['checkbox_usage_flow'])

        main_layout.addLayout(checkbox_layout)
        main_layout = add_line(main_layout)  # 创建一条横线
        # 参数1 销售品信息: 输入框和标签
        param1_layout = QVBoxLayout()
        param1_label = QLabel('主号码销售品信息(命中原则):')
        self.param1_input = QLineEdit()
        param1_layout.addWidget(param1_label)
        param1_layout.addWidget(self.param1_input)
        main_layout.addLayout(param1_layout)
        # 参数2: 输入框和标签
        param2_layout = QVBoxLayout()
        param2_label = QLabel('宽带号销售品信息(命中原则):')
        self.param2_input = QLineEdit()
        param1_layout.addWidget(param2_label)
        param1_layout.addWidget(self.param2_input)
        main_layout.addLayout(param2_layout)
        ###################################################
        # 参数3 销售品信息: 输入框和标签
        param3_layout = QVBoxLayout()
        param3_label = QLabel('主号码销售品信息(反选原则):')
        self.param3_input = QLineEdit()
        param1_layout.addWidget(param3_label)
        param1_layout.addWidget(self.param3_input)
        main_layout.addLayout(param3_layout)
        # 参数4: 输入框和标签
        param4_layout = QVBoxLayout()
        param4_label = QLabel('宽带号销售品信息(反选原则):')
        self.param4_input = QLineEdit()
        param1_layout.addWidget(param4_label)
        param1_layout.addWidget(self.param4_input)
        main_layout.addLayout(param4_layout)
        main_layout = add_line(main_layout)  # 创建一条横线
        ###################################################
        # 添加两个整数输入框在同一行显示
        int_param_layout = QHBoxLayout()
        int_param1_label = QLabel('并发进程数:')
        self.int_param1_input = QSpinBox()  # 整数输入框1
        self.int_param1_input.setRange(1, 20)  # 设置范围
        int_param2_label = QLabel('    |    每并发任务间隔时间(秒)：')
        self.int_param2_input = QSpinBox()  # 整数输入框2
        self.int_param2_input.setRange(1, 10000)  # 设置范围
        int_param_layout.addWidget(int_param1_label)
        int_param_layout.addWidget(self.int_param1_input)
        int_param_layout.addWidget(int_param2_label)
        int_param_layout.addWidget(self.int_param2_input)
        main_layout.addLayout(int_param_layout)
        main_layout = add_line(main_layout)  # 创建一条横线
        # 路径选择区域：输入框 + 按钮
        path_layout = QHBoxLayout()
        # 输入框，用来显示路径
        param3_label = QLabel('导入号码:')
        self.path_input = QLineEdit()
        self.path_input.setPlaceholderText("请输入文件路径或选择文件")
        path_layout.addWidget(param3_label)
        path_layout.addWidget(self.path_input)

        # 按钮：选择文件
        select_button = QPushButton('选择导入文件')
        select_button.clicked.connect(self.select_file)
        path_layout.addWidget(select_button)
        main_layout.addLayout(path_layout)
        ################################################
        # 浏览器路径选择区域：输入框 + 按钮
        path_layout2 = QHBoxLayout()
        # 输入框，用来显示路径
        param4_label = QLabel('浏览器路径:')
        self.path_input2 = QLineEdit()
        self.path_input2.setPlaceholderText("chrome/Chrome.exe")
        path_layout2.addWidget(param4_label)
        path_layout2.addWidget(self.path_input2)
        # 按钮：选择文件
        select_button2 = QPushButton('选择浏览器')
        select_button2.clicked.connect(self.select_browser)
        path_layout2.addWidget(select_button2)
        main_layout.addLayout(path_layout2)
        # 设置窗口布局
        self.setLayout(main_layout)
        self.setWindowTitle('弹出框示例')

        self.setGeometry(100, 100, 300, 200)

        # 按钮区域: 开始、查看进度、导出
        button_layout = QHBoxLayout()

        # 按钮1: 开始按钮
        start_button = QPushButton('开始')
        start_button.clicked.connect(self.on_start_button_click)
        button_layout.addWidget(start_button)

        # 按钮2: 查看进度按钮
        process_button = QPushButton('查看进度')
        process_button.clicked.connect(self.on_process_button_click)
        button_layout.addWidget(process_button)

        # 按钮3: 导出到Excel按钮
        export_button = QPushButton('导出到Excel')
        export_button.clicked.connect(self.on_export_button_click)
        button_layout.addWidget(export_button)

        main_layout.addLayout(button_layout)

        # 刷新采集内容
        show_dict_button = QPushButton('刷新采集内容')
        show_dict_button.clicked.connect(self.show_table_info)
        main_layout.addWidget(show_dict_button)

        # 显示内容区域：表格展示
        self.table_widget = QTableWidget()
        self.table_widget.setColumnCount(0)  # 初始时没有列
        self.table_widget.setRowCount(0)  # 初始时没有行
        main_layout.addWidget(self.table_widget)

        # 获取屏幕的可用区域
        screen = QApplication.primaryScreen()
        rect = screen.availableGeometry()

        # 计算居中位置和设置窗口大小
        width = rect.width() // 2  # 屏幕宽度的一半
        height = rect.height() // 2  # 屏幕高度的一半

        # 计算居中位置
        x = (rect.width() - width) // 2
        y = (rect.height() - height) // 2

        # 设置窗口位置和大小
        self.setGeometry(int(x), int(y),int(width), int(height*1.5))

        self.setWindowTitle('电信业务查询系统')
        self.show()

    def start_background_thread(self):
        """启动后台线程，每3秒调用show_table_info"""
        thread = threading.Thread(target=self.run_background_task)
        thread.daemon = True  # 设置为守护线程
        thread.start()

    def run_background_task(self):
        while True:
            time.sleep(60*10)  # 每*秒执行一次
            self.show_table_info()

    # 开始按钮点击事件
    def on_start_button_click(self):
        print('开始按钮点击')
        # 参数检查
        meta = self.get_checked_status()
        if not self.is_verify_input:
            self.show_popup(msg="请先导入号码")
        else:
            # 1.新建表格
            # create_new_table(meta)
            # 启动后台线程查询表格
            self.start_background_thread()
            # 2.登陆
            self.crawler = Crawler(meta)
            print("开始登录...")
            self.crawler.loggin()
            self.show_popup(msg="请完成登陆后再关闭该页面！")
            # 3.采集
            self.show_popup(msg="点击确认，开始采集")
            print("开始采集...")
            thread = threading.Thread(target=self.crawler.run)
            thread.daemon = True  # 设置为守护线程
            thread.start()

            # print("电话列表：\n", self.conf['phone_list'])

    # 查看进度按钮点击事件
    def on_process_button_click(self):
        if self.crawler:
            index = self.crawler.index
        else:
            index = 0
        if index == 0:
            self.show_popup(msg="当前进度为0，请开始任务后耐心等待")
        else:
            length = len(self.conf.get("phone_list"))
            if index < length:
                percentage = (index/length) * 100
                self.show_popup(msg=f"当前任务进度：【{index}/{length}】\n请耐心等待...{percentage:.2f}%")
            else:
                self.show_popup(msg=f"当前任务已完成【100%】\n可刷新内容查看结果或导出数据")
        print('查看进度按钮点击')

    # 导出按钮点击事件
    def on_export_button_click(self):
        print('导出按钮点击')
        row_count = self.table_widget.rowCount()
        column_count = self.table_widget.columnCount()

        if row_count == 0 or column_count == 0:
            self.show_popup(msg="没有数据可导出！")
            return
        # 创建一个新的工作簿
        workbook = Workbook()
        sheet = workbook.active
        # 写入表头
        for col in range(column_count):
            header_item = self.table_widget.horizontalHeaderItem(col)
            sheet.cell(row=1, column=col + 1, value=header_item.text())
        # 写入数据
        for row in range(row_count):
            for col in range(column_count):
                item = self.table_widget.item(row, col)
                sheet.cell(row=row + 2, column=col + 1, value=item.text() if item else "")
        # 保存文件对话框
        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "Excel Files (*.xlsx);;All Files (*)",
                                                   options=options)
        if file_path:
            workbook.save(file_path)
            self.show_popup(msg="导出成功！")

    # 导入文件功能函数
    def import_file(self):
        # 获取当前路径输入框的内容
        file_path = self.path_input.text()
        if file_path:
            try:
                print(f"确认导入文件：{file_path}")
                with open(file_path, 'r', encoding='utf-8') as f:
                    self.conf["phone_list"] = list(filter(lambda x: x != '', [i.strip() for i in f.readlines()]))
                self.is_verify_input = True
                self.show_popup(msg="导入号码成功！")
            except Exception as e:
                logger.error(f"导入号码失败:\n{e}")
        else:
            print("路径为空，无法导入")

    def show_popup(self, msg="点击确定以关闭此窗口"):
        # 创建一个弹出框，包含确定按钮
        msg_box = QMessageBox(self)
        msg_box.setIcon(QMessageBox.Information)
        msg_box.setWindowTitle("提醒")
        msg_box.setText(msg)
        msg_box.setStandardButtons(QMessageBox.Ok)
        # 使用exec_()确保弹窗在关闭后继续恢复主程序状态
        msg_box.exec_()

    # 路径选择按钮的事件处理函数
    def select_file(self):
        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "所有文件 (*)", options=options)
        if file_path:
            # 显示选择的文件路径到输入框
            self.path_input.setText(file_path)
            self.import_file()

    def select_browser(self):
        options = QFileDialog.Options()
        # 设置过滤器，只选择.exe文件
        filter = "Executable Files (*.exe);;All Files (*)"
        file_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", filter, options=options)
        if file_path:
            # 显示选择的文件路径到输入框
            self.path_input2.setText(file_path)
            self.conf["browser"] = self.path_input2.text()

    # 查表
    def show_table_info(self):
        print("查询表格内容并展示")
        # 清空现有的表格数据
        self.table_widget.setRowCount(0)
        self.table_widget.setColumnCount(0)
        # 连接到SQLite数据库
        try:
            db_file = "db.db"
            if not os.path.exists(db_file):
                # 创建数据库并设置初始表结构
                connection = sqlite3.connect(db_file)
                cursor = connection.cursor()
                # 这里可以根据需要创建表，例如：
                cursor.execute("""CREATE TABLE test (
                                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                                    name TEXT NOT NULL,
                                    position TEXT NOT NULL,
                                    salary REAL NOT NULL)""")
                connection.commit()
                cursor.close()
                connection.close()

            connection = sqlite3.connect(db_file)
            cursor = connection.cursor()
            # 执行查询
            # cursor.execute("SELECT * FROM employees4")
            cursor.execute(f"SELECT * FROM '{self.table_name}' ORDER BY id desc")
            rows = cursor.fetchall()  # 获取所有结果
            # 如果没有数据，弹出提示框
            if not rows:
                # self.show_popup(msg="没有找到任何数据！")
                logger.info("没有找到任何数据！")
                return
            # 设置表格列数和标题
            column_names = [description[0] for description in cursor.description]  # 获取列名
            self.table_widget.setColumnCount(len(column_names))
            self.table_widget.setHorizontalHeaderLabels(column_names)
            # 填充表格数据
            for row_index, row in enumerate(rows):
                self.table_widget.insertRow(row_index)
                for column_index, value in enumerate(row):
                    if not value:
                        value = ""
                    self.table_widget.setItem(row_index, column_index, QTableWidgetItem(str(value)))

        except sqlite3.Error as e:
            logger.error(f"查询数据失败: {e}")
            # self.show_popup(msg="没有找到任何数据！")
        finally:
            if cursor:
                cursor.close()  # 关闭游标
            if connection:
                connection.close()  # 关闭连接

    # 获取勾选框的状态
    def get_checked_status(self):
        meta = {}
        # 获取每个勾选框的勾选状态
        meta["余额"] = self.conf['checkbox_balance'].isChecked()
        meta["归属地"] = self.conf['checkbox_belonging'].isChecked()
        meta["付费方式"] = self.conf['checkbox_paytype'].isChecked()
        meta["服务状态"] = self.conf['checkbox_service_state'].isChecked()
        meta["光猫型号"] = self.conf['checkbox_gpon'].isChecked()
        meta["带宽"] = self.conf['checkbox_bandwidth'].isChecked()
        meta["近3个月账户平均出账"] = self.conf['checkbox_avg_3month'].isChecked()
        meta["副卡数量"] = self.conf['checkbox_additional_num'].isChecked()
        meta["融合类型"] = self.conf['checkbox_fusion_type'].isChecked()
        meta["入网时间"] = self.conf['checkbox_access_time'].isChecked()
        meta["套餐使用查询"] = self.conf['checkbox_usage_minutes'].isChecked()
        meta["套餐费用明细"] = self.conf['checkbox_usage_flow'].isChecked()
        meta["并发进程数"] = int(self.int_param1_input.text())
        meta["每并发任务间隔时间"] = int(self.int_param2_input.text())
        meta["主号码销售品信息"] = list(filter(lambda x: x != '', [i.strip() for i in self.param1_input.text().split(",")]))
        meta["宽带号销售品信息"] = list(filter(lambda x: x != '', [i.strip() for i in self.param2_input.text().split(",")]))
        meta["主号码销售品信息-排除项"] = list(filter(lambda x: x != '', [i.strip() for i in self.param3_input.text().split(",")]))
        meta["宽带号销售品信息-排除项"] = list(filter(lambda x: x != '', [i.strip() for i in self.param4_input.text().split(",")]))
        meta["table_name"] = self.table_name
        meta["browser"] = self.get_browser_path()
        meta["phone_list"] = self.conf.get("phone_list") if self.conf.get("phone_list") else self.get_phone_list()
        print(json.dumps(meta, indent=4, ensure_ascii=False))
        return meta

    def get_phone_list(self):
        phone_input_path = self.path_input.text()
        if not phone_input_path:
            self.is_verify_input = False
            return
        else:
            with open(phone_input_path, 'r', encoding='utf-8') as f:
                self.conf["phone_list"] = list(filter(lambda x: x != '', [i.strip() for i in f.readlines()]))
            self.is_verify_input = True
        return self.conf["phone_list"]

    def get_browser_path(self):
        browser_path = self.path_input2.text()
        return browser_path if browser_path else self.conf["browser"]
    def closeEvent(self, event):
        """重写关闭事件，添加确认退出提示"""
        reply = QMessageBox.question(self, '确认退出',
                                     "是否真的要退出？",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()  # 允许关闭窗口
        else:
            event.ignore()  # 忽略关闭事件


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    ex.show()
    sys.exit(app.exec_())
